package com.example.testservice.netty;

import android.util.Log;

import com.example.testservice.MainActivity;
import com.example.testservice.eventBusBean.ConnectStatusBean;
import com.haoxy.common.model.MessageBean;

import org.greenrobot.eventbus.EventBus;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;

public class NettyService {
    public static final String TAG = "NETTY_TAG";
    private static volatile NettyService mInstance = null;
    //自定义分隔符设置
    public static final String PACKETSEPARATOR = "\n";

    private EventLoopGroup bossGroup;//表示监听端口
    private EventLoopGroup workerGroup;//表示处理每一条连接的数据读写的线程组
    private ServerBootstrap bootstrap;
    private ChannelInitServer channelInitServer;////给服务端 Channel 指定处理逻辑的 Handler
    public volatile Channel channel;//连接通道

    public static NettyService getInstance() {
        if (mInstance == null) {
            synchronized (NettyService.class) {
                if (mInstance == null) {
                    mInstance = new NettyService();
                }
            }
        }
        return mInstance;
    }

    /**
     * 启动netty客户端
     */
    public void start() {
        Executors.newSingleThreadScheduledExecutor().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    bootstrap = new ServerBootstrap();
                    channelInitServer = new ChannelInitServer();
                    bossGroup = new NioEventLoopGroup();//表示监听端口
                    workerGroup = new NioEventLoopGroup();//表示处理每一条连接的数据读写的线程组
                    bootstrap.group(bossGroup, workerGroup)
                            .channel(NioServerSocketChannel.class)//指定为NIO模型
                            .option(ChannelOption.MAX_MESSAGES_PER_READ,16)//一次Loop读取的最大消息数，对于ServerChannel或者NioByteChannel，默认值为16，其他Channel默认值为1
                            .option(ChannelOption.SO_BACKLOG, 1024)//链接缓冲池的大小（ServerSocketChannel的设置）
                            .option(ChannelOption.TCP_NODELAY, true)//是否使用Nagle算法，设置为true关闭Nagle算法。 如果是时延敏感型的应用，建议关闭。 Nagle算法将小的碎片数据连接成更大的报文来最小化所发送的报文的数量。
                            .option(ChannelOption.SO_KEEPALIVE, true)//维持链接的活跃，清除死链接(SocketChannel的设置)
                            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                            .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                            .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
//                            .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(DEFAULT_MIN_SIZE, DEFAULT_INITIAL_SIZE, DEFAULT_MAX_SIZE));
                            .childOption(ChannelOption.SO_RCVBUF, 1024 * 1024 * 5)
                            .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024 * 5)
//                            .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * 5)
//                            .option(ChannelOption.SO_SNDBUF, 1024 * 1024 * 5)
                            .childHandler(channelInitServer);//设置handler
                    ChannelFuture future = bootstrap.bind(MainActivity.PORT).sync();
                    channel = future.channel();
                    //端口频道打开监听
                    future.addListener(new ChannelFutureListener() {
                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {
                            if (!future.isSuccess()) {
                                EventBus.getDefault().post(new ConnectStatusBean("2"));
                                Log.w(TAG, "服务端启动失败");
                            } else {
                                Log.w(TAG, "等待连接：");
                            }
                        }
                    });
                    channel.closeFuture().sync();
                } catch (Exception e) {
                    EventBus.getDefault().post(new ConnectStatusBean("2"));
                    e.printStackTrace();
                    Log.w(TAG, "服务端启动失败 err:" + e.getMessage());
                } finally {
                    workerGroup.shutdownGracefully();
                    bossGroup.shutdownGracefully();
                }

            }
        });
    }

    /**
     * 线程处理类及心跳时间设置
     */
    public class ChannelInitServer extends ChannelInitializer<SocketChannel> {

        public NettyDataHandler nettyDataHandler = new NettyDataHandler();

        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            try {
                ChannelPipeline channelPipeline = ch.pipeline();
                //添加心跳机制，例：每1000ms发送一次心跳
                channelPipeline.addLast(new IdleStateHandler(3000, 3000, 3000, TimeUnit.MILLISECONDS));
                //object编码器
                channelPipeline.addLast(new ObjectEncoder());
                //object解码器
                channelPipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null)));
                //自定义专门处理业务逻辑的 Handler,添加数据处理（接收、发送、心跳）
                channelPipeline.addLast(nettyDataHandler);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭服务端
     */
    public void stop() {
        Log.w(TAG, "channel != null====" + (channel != null));
        if (channel != null) {
            channel.close();
            channel = null;
            Log.w(TAG, "已关闭");
        }
        mInstance = null;
    }

    /**
     * 发送数据
     *
     * @param messageBean
     */
    public void sendMessage(MessageBean messageBean) {
        channelInitServer.nettyDataHandler.sendMessage(messageBean);
    }
}
